///////////////////////////////////////////////////////////////////////
//  Siglaz.Graphic
///////////////////////////////////////////////////////////////////////

Siglaz.Graphic = function(id, width, height){
	//start preparing for canvas drawing
	var dom = document.getElementById(id);
	width = (width === undefined) ? "800px" : width + "px";
	height = (height === undefined) ? "600px" : height + "px";
	
	var id_div = "sig_div_drawing";
	var id_main_canvas = "sig_drawing_canvas";
	var id_buffer_canvas = "sig_buffering_canvas";
	
	var div_drawing = document.createElement("div");
	div_drawing.setAttribute("id", id_div);
	div_drawing.setAttribute("style", "position: relative; width: " + width + "; height: " + height + ";");
	dom.appendChild(div_drawing);
	
	var drawing_canvas = document.createElement("canvas");
	drawing_canvas.setAttribute("id", id_main_canvas);
	drawing_canvas.setAttribute("width", width);
	drawing_canvas.setAttribute("height", height);
	drawing_canvas.setAttribute("style", "position:absolute;");
	
	var buffer_canvas = drawing_canvas.cloneNode(false);
	buffer_canvas.setAttribute("id", id_buffer_canvas);
	
	div_drawing.appendChild(drawing_canvas);	
	div_drawing.appendChild(buffer_canvas);	
	//end preparing for canvas drawing
	
	//setup for graphic object 
	this._canvas = document.getElementById(id_main_canvas);
	this._buffer = document.getElementById(id_buffer_canvas);
	
	this._ctx = this._canvas.getContext("2d");
	this._ctx_buffer = this._buffer.getContext("2d");
    this._shapes = [];
    
	this._options = {
		height: this._ctx.canvas.height,
		width: this._ctx.canvas.width,
		matrix: null,
		iMatrix: null,
		canZoomOut: true,
		canZoomIn: true,
		canDrag: true
	}
	
	this._check = {
		isdragging: false
	}
	
	this.beginListen();
}

Siglaz.Graphic.prototype = {
	beginListen: function(){
		var graphic = this;
		var event = ["click", "mousemove", "mousedown", "mouseup"]; //"mouseover", "mouseout"
		for(var i in event)
			this._buffer.addEventListener(event[i], function(e){
				graphic.checkEvent(e);
			});
		this._buffer.onmousewheel = function(e){
			graphic.actionZoomToMousePos(e);
		}
		
		var b_point = {x: 0, y: 0};
		var isdragging = false;
		this._buffer.onmousedown = function(e){
			if(graphic.isCanDrag() == true)
			{
				console.log("begin drag");
				isdragging = true;
				b_point = graphic.getMousePos(e);
				console.log(b_point.x + " " + b_point.y);
			}
			
		}
		this._buffer.onmouseup = function(e){
			
			if(isdragging == true)
			{
				isdragging = false;
				console.log("end drag");
			}
				
		}
		this._buffer.onmousemove = function(e){
			if (isdragging == true) {
				console.log("dragging");
				e_point = graphic.getMousePos(e);
				
				var m = graphic.getInvertTransform();
				var t_b_point = Siglaz.Util.transformPoint(m, b_point.x, b_point.y);
				var t_e_point = Siglaz.Util.transformPoint(m, e_point.x, e_point.y);
				
				distance = {
					x: t_e_point.x - t_b_point.x,
					y: t_e_point.y - t_b_point.y
				};
				
				b_point = e_point;
				graphic.translate(distance.x, distance.y);
				graphic.draw();
			}
		}
	},
	actionZoomToMousePos: function(e){
		if((this.isCanZoomOut() == false && e.wheelDelta < 0) || (this.isCanZoomIn() == false && e.wheelDelta > 0))
			return;
		var zoom = e.wheelDelta > 0 ? 3/2 : 2/3;
		this.zoomToMousePos(e, zoom, zoom);
		this.draw();
	},
	checkEvent: function(e){
		var mousePos = this.getMousePos(e);
		var m = this.getTransform();
		m = Siglaz.Util.invertMatrix(m);
		var p = Siglaz.Util.transformPoint(m, mousePos.x, mousePos.y);
		
		for(var i in this._shapes)
			this._shapes[i]._onEvent(e, p.x, p.y, this);
	},
	isCanZoomIn: function(){
		return this._options.canZoomIn;
	},
	isCanZoomOut: function(){
		return this._options.canZoomOut;
	},
	setCanZoomOut: function(can){
		this._options.canZoomOut = can;
	},
	setCanZoomIn: function(can){
		this._options.canZoomIn = can;
	},
	isCanDrag: function(){
		return this._options.canDrag;
	},
	setCanDrag: function(can){
		this._options.canDrag = can;
	},
	
	/**
	 * Set visible for all shapes
	 * @param: {bool} visible
	 */
	setVisibleAll: function(visible){
		for(var i in this._shapes)
			this._shapes[i].setVisible(visible);
	},
	/**
	 * Set visible for one or more shapes
	 * @param: {Array/Siglaz.Shape} shapes
	 * @param: {bool} visible
	 */
	setVisible: function(shapes, visible){
		if(shapes instanceof Array)
			for(var i in shapes)
				this.shapes[i].setVisible(visible);
		else
			this.shapes.setVisible(visible);
	},
	getMousePos: function(e){
		var obj = this._canvas;
	    var top = 0;
	    var left = 0;
	    while (obj && obj.tagName != 'BODY') {
	        top += obj.offsetTop;
	        left += obj.offsetLeft;
	        obj = obj.offsetParent;
	    }
	    // return relative mouse position
	    var mouseX = e.clientX - left + window.pageXOffset;
	    var mouseY = e.clientY - top + window.pageYOffset;
	    return {
	        x: mouseX,
	        y: mouseY
	    };
	},
	indexOfShape: function(shape){
		var length = this._shapes.length;
        for (var i = 0; i < length; i++) {
            if (shape == this._shapes[i]) {
                return i;
            }
        }
        return -1;
	},
	add: function(shape){
		if(shape instanceof Array)
			for (var i in shape)
	        	this._shapes.push(shape[i]);
		else
			this._shapes.push(shape);
	},
	remove: function(index){
		this._shapes.splice(index, 1);
	},
	removeAll: function(){
		if (this._shapes != null)
        	this._shapes.length = 0;
	},
	getDefaultMatrix: function(){
		return [1, 0, 0, 1, 0, 0];
	},
	getTransform: function(){
		if(this._options.matrix == null)
			return this.getDefaultMatrix();
		return this._options.matrix;
	},
	getInvertTransform: function(){
		if(this._options.iMatrix == null)
			return this.getDefaultMatrix();
		return this._options.iMatrix;
	},
	getWidth: function(){
		return this._options.width;
	},
	getHeight: function(){
		return this._options.height;
	},
	setTransform: function(matrix){
		this._options.matrix = matrix;
		this._options.iMatrix = Siglaz.Util.invertMatrix(matrix);
	},
	resetTransform: function(){
		this.setTransform(null);
	},
	zoom: function(sx, sy){
		var m = this.getTransform();
		m[0] *= sx;
		m[1] *= sx;
		m[2] *= sy;
		m[3] *= sy;
		this.setTransform(m);
	},
	zoomToPoint: function(x, y, sx, sy){
		this.translate(x, y);
		this.zoom(sx, sy);
		this.translate(-x, -y);
	},
	zoomToMousePos: function(e, sx, sy){
		var pos = this.getMousePos(e);
		this.zoomToPoint(pos.x, pos.y, sx, sy);
	},
	translate: function(x, y)
	{
		var m = this.getTransform();
		m[4] += m[0] * x + m[2] * y;
		m[5] += m[1] * x + m[3] * y;
		this.setTransform(m);
	},
	drawSelectedObject: function(){
		this.clearDraw(this._ctx_buffer);
		
		if (this.getTransform() != this.getDefaultMatrix()) {
	        this._ctx_buffer.save();    
	        this.applyTransform(this._ctx_buffer);
	    }
	    
	    if (this._shapes != null)
	        for (var i in this._shapes){
	        	if(this._shapes[i].isSelected() == true)
	        		this._shapes[i].drawBorder(this._ctx_buffer);
        	}
	        
	    // other graphics
	    if (this.getTransform() != this.getDefaultMatrix())
	        this._ctx_buffer.restore();
	},
	applyTransform : function(graphic) {
		var m = this.getTransform();
		graphic.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
	},
	clearDraw: function(graphic){
		graphic.clearRect(0, 0, this.getWidth(), this.getWidth());
	},
	draw: function(){
		this.drawVisibleShapes();
		this.drawSelectedObject();
	},
	drawVisibleShapes: function(){
		this.clearDraw(this._ctx);
		
		if (this.getTransform() != this.getDefaultMatrix()) {
	        this._ctx.save();    
	        this.applyTransform(this._ctx);
	    }
	    
	    if (this._shapes != null)
	        for (var i in this._shapes)
        		this._shapes[i].draw(this._ctx);
	        
	    // other graphics
	    if (this.getTransform() != this.getDefaultMatrix())
	        this._ctx.restore();
	},
	getSelectedShapes: function(){
		var shapes = [];
		for(var i in this._shapes)
		{
			if(this._shapes[i]._options.selected == true)
				shapes.push(this._shapes[i]);
		}
		return shapes;
	},
	parseShapeToJson: function(){
		return Siglaz.Util.serialize(this._shapes);
	},
	parseShapeFromJson: function(json){
		var objects = Siglaz.Util.deserialize(json);
		this.add(objects);		
	}
}